home *** CD-ROM | disk | FTP | other *** search
/ InfoMagic Internet Tools 1993 July / Internet Tools.iso / RockRidge / ip / slip / cslip-2.6 / tip / remcap.c < prev    next >
Encoding:
C/C++ Source or Header  |  1990-06-30  |  9.0 KB  |  417 lines

  1. /*
  2.  * Copyright (c) 1983 The Regents of the University of California.
  3.  * All rights reserved.
  4.  *
  5.  * Redistribution and use in source and binary forms are permitted
  6.  * provided that: (1) source distributions retain this entire copyright
  7.  * notice and comment, and (2) distributions including binaries display
  8.  * the following acknowledgement:  ``This product includes software
  9.  * developed by the University of California, Berkeley and its contributors''
  10.  * in the documentation or other materials provided with the distribution
  11.  * and in all advertising materials mentioning features or use of this
  12.  * software. Neither the name of the University nor the names of its
  13.  * contributors may be used to endorse or promote products derived
  14.  * from this software without specific prior written permission.
  15.  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
  16.  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
  17.  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
  18.  */
  19.  
  20. #ifndef lint
  21. static char sccsid[] = "@(#)remcap.c    5.2 (Berkeley) 9/2/88";
  22. #endif /* not lint */
  23.  
  24. /*
  25.  * remcap - routines for dealing with the remote host data base
  26.  *
  27.  * derived from termcap
  28.  */
  29. #include <sys/file.h>
  30. #include <ctype.h>
  31.  
  32. #ifndef BUFSIZ
  33. #define    BUFSIZ        1024
  34. #endif
  35. #define MAXHOP        32        /* max number of tc= indirections */
  36. #define SYSREMOTE    "/etc/remote"    /* system remote file */
  37.  
  38. #define    tgetent        rgetent
  39. #define    tnchktc        rnchktc
  40. #define    tnamatch    rnamatch
  41. #define    tgetnum        rgetnum
  42. #define    tgetflag    rgetflag
  43. #define    tgetstr        rgetstr
  44. #define    E_TERMCAP    RM = SYSREMOTE
  45. #define V_TERMCAP    "REMOTE"
  46. #define V_TERM        "HOST"
  47.  
  48. char    *RM;
  49.  
  50. /*
  51.  * termcap - routines for dealing with the terminal capability data base
  52.  *
  53.  * BUG:        Should use a "last" pointer in tbuf, so that searching
  54.  *        for capabilities alphabetically would not be a n**2/2
  55.  *        process when large numbers of capabilities are given.
  56.  * Note:    If we add a last pointer now we will screw up the
  57.  *        tc capability. We really should compile termcap.
  58.  *
  59.  * Essentially all the work here is scanning and decoding escapes
  60.  * in string capabilities.  We don't use stdio because the editor
  61.  * doesn't, and because living w/o it is not hard.
  62.  */
  63.  
  64. static    char *tbuf;
  65. static    int hopcount;    /* detect infinite loops in termcap, init 0 */
  66. static char *tskip();
  67. char    *tgetstr();
  68. static char *tdecode();
  69. char    *getenv();
  70. static    char *remotefile;
  71.  
  72. /*
  73.  * Get an entry for terminal name in buffer bp,
  74.  * from the termcap file.  Parse is very rudimentary;
  75.  * we just notice escaped newlines.
  76.  */
  77. tgetent(bp, name)
  78.     char *bp, *name;
  79. {
  80.     char lbuf[BUFSIZ], *cp, *p;
  81.     int rc1, rc2;
  82.  
  83.     remotefile = cp = getenv(V_TERMCAP);
  84.     if (cp == (char *)0 || strcmp(cp, SYSREMOTE) == 0) {
  85.         remotefile = cp = SYSREMOTE;
  86.         return (getent(bp, name, cp));
  87.     } else {
  88.         if ((rc1 = getent(bp, name, cp)) != 1)
  89.             *bp = '\0';
  90.         remotefile = cp = SYSREMOTE;
  91.         rc2 = getent(lbuf, name, cp);
  92.         if (rc1 != 1 && rc2 != 1)
  93.             return (rc2);
  94.         if (rc2 == 1) {
  95.             p = lbuf;
  96.             if (rc1 == 1)
  97.                 while (*p++ != ':')
  98.                     ;
  99.             if (strlen(bp) + strlen(p) > BUFSIZ) {
  100.                 write(2, "Remcap entry too long\n", 23);
  101.                 return (-1);
  102.             }
  103.             strcat(bp, p);
  104.         }
  105.         tbuf = bp;
  106.         return (1);
  107.     }
  108. }
  109.  
  110. getent(bp, name, cp)
  111.     char *bp, *name, *cp;
  112. {
  113.     register int c;
  114.     register int i = 0, cnt = 0;
  115.     char ibuf[BUFSIZ], *cp2;
  116.     int tf;
  117.  
  118.     tbuf = bp;
  119.     tf = 0;
  120.     /*
  121.      * TERMCAP can have one of two things in it. It can be the
  122.      * name of a file to use instead of /etc/termcap. In this
  123.      * case it better start with a "/". Or it can be an entry to
  124.      * use so we don't have to read the file. In this case it
  125.      * has to already have the newlines crunched out.
  126.      */
  127.     if (cp && *cp) {
  128.         if (*cp!='/') {
  129.             cp2 = getenv(V_TERM);
  130.             if (cp2 == (char *)0 || strcmp(name,cp2) == 0) {
  131.                 strcpy(bp,cp);
  132.                 return (tnchktc());
  133.             } else
  134.                 tf = open(E_TERMCAP, O_RDONLY);
  135.         } else
  136.             tf = open(RM = cp, O_RDONLY);
  137.     }
  138.     if (tf == 0)
  139.         tf = open(E_TERMCAP, O_RDONLY);
  140.     if (tf < 0)
  141.         return (-1);
  142.     for (;;) {
  143.         cp = bp;
  144.         for (;;) {
  145.             if (i == cnt) {
  146.                 cnt = read(tf, ibuf, BUFSIZ);
  147.                 if (cnt <= 0) {
  148.                     close(tf);
  149.                     return (0);
  150.                 }
  151.                 i = 0;
  152.             }
  153.             c = ibuf[i++];
  154.             if (c == '\n') {
  155.                 if (cp > bp && cp[-1] == '\\') {
  156.                     cp--;
  157.                     continue;
  158.                 }
  159.                 break;
  160.             }
  161.             if (cp >= bp+BUFSIZ) {
  162.                 write(2,"Remcap entry too long\n", 23);
  163.                 break;
  164.             } else
  165.                 *cp++ = c;
  166.         }
  167.         *cp = 0;
  168.  
  169.         /*
  170.          * The real work for the match.
  171.          */
  172.         if (tnamatch(name)) {
  173.             close(tf);
  174.             return (tnchktc());
  175.         }
  176.     }
  177. }
  178.  
  179. /*
  180.  * tnchktc: check the last entry, see if it's tc=xxx. If so,
  181.  * recursively find xxx and append that entry (minus the names)
  182.  * to take the place of the tc=xxx entry. This allows termcap
  183.  * entries to say "like an HP2621 but doesn't turn on the labels".
  184.  * Note that this works because of the left to right scan.
  185.  */
  186. tnchktc()
  187. {
  188.     register char *p, *q;
  189.     char tcname[16];    /* name of similar terminal */
  190.     char tcbuf[BUFSIZ];
  191.     char *holdtbuf = tbuf;
  192.     int l;
  193.     char *cp;
  194.  
  195.     p = tbuf + strlen(tbuf) - 2;    /* before the last colon */
  196.     while (*--p != ':')
  197.         if (p<tbuf) {
  198.             write(2, "Bad remcap entry\n", 18);
  199.             return (0);
  200.         }
  201.     p++;
  202.     /* p now points to beginning of last field */
  203.     if (p[0] != 't' || p[1] != 'c')
  204.         return (1);
  205.     strcpy(tcname, p+3);
  206.     q = tcname;
  207.     while (*q && *q != ':')
  208.         q++;
  209.     *q = 0;
  210.     if (++hopcount > MAXHOP) {
  211.         write(2, "Infinite tc= loop\n", 18);
  212.         return (0);
  213.     }
  214.     if (getent(tcbuf, tcname, remotefile) != 1) {
  215.         if (strcmp(remotefile, SYSREMOTE) == 0)
  216.             return (0);
  217.         else if (getent(tcbuf, tcname, SYSREMOTE) != 1)
  218.             return (0);
  219.     }
  220.     for (q = tcbuf; *q++ != ':'; )
  221.         ;
  222.     l = p - holdtbuf + strlen(q);
  223.     if (l > BUFSIZ) {
  224.         write(2, "Remcap entry too long\n", 23);
  225.         q[BUFSIZ - (p-holdtbuf)] = 0;
  226.     }
  227.     strcpy(p, q);
  228.     tbuf = holdtbuf;
  229.     return (1);
  230. }
  231.  
  232. /*
  233.  * Tnamatch deals with name matching.  The first field of the termcap
  234.  * entry is a sequence of names separated by |'s, so we compare
  235.  * against each such name.  The normal : terminator after the last
  236.  * name (before the first field) stops us.
  237.  */
  238. tnamatch(np)
  239.     char *np;
  240. {
  241.     register char *Np, *Bp;
  242.  
  243.     Bp = tbuf;
  244.     if (*Bp == '#')
  245.         return (0);
  246.     for (;;) {
  247.         for (Np = np; *Np && *Bp == *Np; Bp++, Np++)
  248.             continue;
  249.         if (*Np == 0 && (*Bp == '|' || *Bp == ':' || *Bp == 0))
  250.             return (1);
  251.         while (*Bp && *Bp != ':' && *Bp != '|')
  252.             Bp++;
  253.         if (*Bp == 0 || *Bp == ':')
  254.             return (0);
  255.         Bp++;
  256.     }
  257. }
  258.  
  259. /*
  260.  * Skip to the next field.  Notice that this is very dumb, not
  261.  * knowing about \: escapes or any such.  If necessary, :'s can be put
  262.  * into the termcap file in octal.
  263.  */
  264. static char *
  265. tskip(bp)
  266.     register char *bp;
  267. {
  268.  
  269.     while (*bp && *bp != ':')
  270.         bp++;
  271.     if (*bp == ':')
  272.         bp++;
  273.     return (bp);
  274. }
  275.  
  276. /*
  277.  * Return the (numeric) option id.
  278.  * Numeric options look like
  279.  *    li#80
  280.  * i.e. the option string is separated from the numeric value by
  281.  * a # character.  If the option is not found we return -1.
  282.  * Note that we handle octal numbers beginning with 0.
  283.  */
  284. tgetnum(id)
  285.     char *id;
  286. {
  287.     register int i, base;
  288.     register char *bp = tbuf;
  289.  
  290.     for (;;) {
  291.         bp = tskip(bp);
  292.         if (*bp == 0)
  293.             return (-1);
  294.         if (*bp++ != id[0] || *bp == 0 || *bp++ != id[1])
  295.             continue;
  296.         if (*bp == '@')
  297.             return (-1);
  298.         if (*bp != '#')
  299.             continue;
  300.         bp++;
  301.         base = 10;
  302.         if (*bp == '0')
  303.             base = 8;
  304.         i = 0;
  305.         while (isdigit(*bp))
  306.             i *= base, i += *bp++ - '0';
  307.         return (i);
  308.     }
  309. }
  310.  
  311. /*
  312.  * Handle a flag option.
  313.  * Flag options are given "naked", i.e. followed by a : or the end
  314.  * of the buffer.  Return 1 if we find the option, or 0 if it is
  315.  * not given.
  316.  */
  317. tgetflag(id)
  318.     char *id;
  319. {
  320.     register char *bp = tbuf;
  321.  
  322.     for (;;) {
  323.         bp = tskip(bp);
  324.         if (!*bp)
  325.             return (0);
  326.         if (*bp++ == id[0] && *bp != 0 && *bp++ == id[1]) {
  327.             if (!*bp || *bp == ':')
  328.                 return (1);
  329.             else if (*bp == '@')
  330.                 return (0);
  331.         }
  332.     }
  333. }
  334.  
  335. /*
  336.  * Get a string valued option.
  337.  * These are given as
  338.  *    cl=^Z
  339.  * Much decoding is done on the strings, and the strings are
  340.  * placed in area, which is a ref parameter which is updated.
  341.  * No checking on area overflow.
  342.  */
  343. char *
  344. tgetstr(id, area)
  345.     char *id, **area;
  346. {
  347.     register char *bp = tbuf;
  348.  
  349.     for (;;) {
  350.         bp = tskip(bp);
  351.         if (!*bp)
  352.             return (0);
  353.         if (*bp++ != id[0] || *bp == 0 || *bp++ != id[1])
  354.             continue;
  355.         if (*bp == '@')
  356.             return (0);
  357.         if (*bp != '=')
  358.             continue;
  359.         bp++;
  360.         return (tdecode(bp, area));
  361.     }
  362. }
  363.  
  364. /*
  365.  * Tdecode does the grung work to decode the
  366.  * string capability escapes.
  367.  */
  368. static char *
  369. tdecode(str, area)
  370.     register char *str;
  371.     char **area;
  372. {
  373.     register char *cp;
  374.     register int c;
  375.     register char *dp;
  376.     int i;
  377.  
  378.     cp = *area;
  379.     while ((c = *str++) && c != ':') {
  380.         switch (c) {
  381.  
  382.         case '^':
  383.             c = *str++ & 037;
  384.             break;
  385.  
  386.         case '\\':
  387.             dp = "E\033^^\\\\::n\nr\rt\tb\bf\f";
  388.             c = *str++;
  389. nextc:
  390.             if (*dp++ == c) {
  391.                 c = *dp++;
  392.                 break;
  393.             }
  394.             dp++;
  395.             if (*dp)
  396.                 goto nextc;
  397.             if (isdigit(c)) {
  398.                 c -= '0', i = 2;
  399.                 do
  400.                     c <<= 3, c |= *str++ - '0';
  401.                 while (--i && isdigit(*str));
  402.                 break;
  403.               }
  404.             /* \x where x is not understood is passed as \x */
  405.             /* to allow the handshake routine to do further */
  406.             /* escape processing.                */
  407.             *cp++ = '\\';
  408.             break;
  409.         }
  410.         *cp++ = c;
  411.     }
  412.     *cp++ = 0;
  413.     str = *area;
  414.     *area = cp;
  415.     return (str);
  416. }
  417.